#!/bin/sh

. $LKP_SRC/lib/env.sh

escape_cgi_param()
{
	local uri="$1"
	# uri=${uri//%/%25} # must be the first one
	# uri=${uri//+/%2B}
	# uri=${uri//&/%26}
	# uri=${uri//\?/%3F}
	# uri=${uri//@/%40}
	# uri=${uri//:/%3A}
	# uri=${uri//;/%3D}
	echo "$uri" |
	sed -r	-e 's/%/%25/g' \
		-e 's/\+/%2B/g' \
		-e 's/&/%26/g' \
		-e 's/#/%23/g' \
		-e 's/\?/%3F/g' \
		-e 's/ /%20/g'
}

reset_broken_ipmi()
{
	[ -x '/usr/sbin/bmc-device' ] || return

	bmc-device --cold-reset
}

#
# job handling at client is finished, tell server to do some
# post handling, such as delete the job file, process all
# monitors data, and so on
#
trigger_post_process()
{
    local query_str=job_file=$(escape_cgi_param "$job")
    query_str="${query_str}&$(escape_cgi_param "job_id=$id")"
    local cgi_uri="~lkp/cgi-bin/lkp-post-run?$query_str"
    http_get_cgi "$cgi_uri"
}

jobfile_append_var()
{
	[ -n "$job" ] || return

	# input example: "var1=value1" "var2=value2 value_with_space" ....
	[ -z "$*" ] && LOG_ERROR "no paramter specified at $FUNCTION" && return

	local query_str=job_file=$(escape_cgi_param "$job")
	query_str="${query_str}&$(escape_cgi_param "job_id=$id")"
	for assignment in "$@"; do
		query_str="${query_str}&$(escape_cgi_param "$assignment")"
	done

	if [ -n "$sched_host" ]; then # new scheduler
		http_post "scheduler/v1/jobs/$id/update?$query_str"
	else
		http_get_cgi "cgi-bin/lkp-jobfile-append-var?$query_str"
	fi
}

# this obsoletes jobfile_append_var() for new scheduler
update_job_vars()
{
	local query_str=""
	for assignment in "$@"; do
		query_str="${query_str}&$(escape_cgi_param "$assignment")"
	done

	http_post "scheduler/v1/jobs/$id/update?${query_str#&}"
}

# called by cluster nodes
wait_peer_jobs() {
    # Capture the JSON output from wait.sh
    local json=$($LKP_SRC/sbin/wait.sh --get-fields node_roles,ip,direct_ips "$@")

    check_fail_fast || return
    parse_wait_peer
}

# Input JSON example
# json='{
#   "fail_fast": {
#     "failed_job": "job_id"
#   }
# }'
check_fail_fast() {
    # Extract the value of fail_fast.failed_job using awk
    local failed_job=$(echo "$json" | awk -F'"' '
      /"fail_fast": {/ {in_fail_fast=1}
      in_fail_fast && /"failed_job":/ {print $4; exit}
    ')

    # Check if fail_fast is set and not null
    if [ -n "$failed_job" ]; then
        echo "Peer job failed ($failed_job)"
        return 1
    else
        return 0
    fi
}

# input: wait.sh result json looks like this yaml, but in pretty json format
#   wait_options:
#     fail_fast: null or failed-jobid
#   waited_jobs:
#     id1:
#     	job_stage: finish
# 	node_roles: server
# 	ip: aaa
# 	direct_ips: bbb ccc
#     id2:
#     	job_stage: finish
# 	node_roles: client
# 	ip: xxx
# 	direct_ips: yyy zzz
# output: parse waited_jobs fields, collect all ips from all job roles and save to shell vars
#   role_client_ip=xxx
#   role_client_direct_ips="yyy zzz"
#   role_server_ip=aaa
#   role_server_direct_ips="bbb ccc"
parse_wait_peer() {
    local line
    local current_id=""
    local current_roles=""
    local current_ip=""
    local current_direct_ips=""
    local in_job=false

    # Write the JSON content to a temporary file
    TMP_JSON=$(mktemp -t parse_wait_peer-XXXXXX)
    echo "$json" > $TMP_JSON

    # Read the JSON input line by line from the temporary file
    while IFS= read -r line; do
        # Check if the line starts a new job entry
        if echo "$line" | grep -q '"[a-zA-Z0-9_]\+": {'; then
            current_id=$(echo "$line" | sed 's/^[[:space:]]*"\([^"]*\)"[[:space:]]*:[[:space:]]*{.*/\1/')
            in_job=true
        elif $in_job; then
            # Extract node_roles
            if echo "$line" | grep -q '"node_roles":'; then
                current_roles=$(echo "$line" | cut -d '"' -f 4 | xargs)
            fi

            # Extract ip
            if echo "$line" | grep -q '"ip":'; then
                current_ip=$(echo "$line" | cut -d '"' -f 4)
            fi

            # Extract direct_ips
            if echo "$line" | grep -q '"direct_ips":'; then
                current_direct_ips=$(echo "$line" | cut -d '"' -f 4)
            fi

            # Check if the job entry ends
            if echo "$line" | grep -q '^[[:space:]]*}'; then
                # Process roles for the current job
                role_list=$(echo "$current_roles" | xargs)  # Trim spaces and split roles
                for role in $(echo "$role_list"); do
                    if [ -z "$role" ]; then
                        continue  # Skip empty roles
                    fi
                    var_ip="role_${role}_ip"
                    var_direct="role_${role}_direct_ips"

                    # Append IP and direct IPs to the corresponding variables
                    eval "existing_ip=\$$var_ip"
                    if [ -n "$existing_ip" ]; then
                        new_ip="$existing_ip $current_ip"
                    else
                        new_ip="$current_ip"
                    fi
                    eval "$var_ip=\"$new_ip\""

                    eval "existing_direct=\$$var_direct"
                    if [ -n "$existing_direct" ]; then
                        new_direct="$existing_direct $current_direct_ips"
                    else
                        new_direct="$current_direct_ips"
                    fi
                    eval "$var_direct=\"$new_direct\""
                done

                # Reset job details
                current_id=""
                current_roles=""
                current_ip=""
                current_direct_ips=""
                in_job=false
            fi
        fi
    done < $TMP_JSON

    # Clean up the temporary file
    rm -f $TMP_JSON
}

report_job_step()
{
	[ -n "$1" ] || return

	local step=$1

	http_get_cgi "cgi-bin/report-job-step?jobid=$id&step=$step"
}

set_job_state()
{
	[ -n "$1" ] || return
	jobfile_append_var "job_state=$1"
}

set_job_stage()
{
	[ -n "$1" ] || return

	url="cgi-bin/set-job-stage?job_stage=$1&job_id=$id"
	[ -n "$2" ] && url="${url}&timeout=$2"

	http_get_cgi $url
}

set_tbox_wtmp()
{
	local tbox_state="$1"
	[ -n "$tbox_state" ] || return

	# disable since useless
	# http_get_cgi "cgi-bin/lkp-wtmp?tbox_name=$HOSTNAME&tbox_state=$tbox_state&mac=$PUB_MAC&ip=$PUB_IP&job_id=$id"
}

report_ssh_info()
{
    local ssh_port="$1"
    local message="$2"

    if [ -n "$sched_host" ]; then  # new scheduler
        local http_prefix="http://$sched_host:${sched_port:-3000}"
    else
        local http_prefix="http://$LKP_SERVER:${LKP_CGI_PORT:-3000}"
    fi

    content='{"tbox_name": "'$HOSTNAME'", "job_id": "'$id'", "ssh_port": "'$ssh_port'", "message": "'$message'"}'
    curl -XPOST "$http_prefix/~lkp/cgi-bin/report_ssh_info" -d "$content"
}

####################################################

http_escape_request()
{
	local path="$(escape_cgi_param "$1")"
	shift
	http_do_request "$path" "$@"
}

http_do_request()
{
	local path="$1"
	shift

	[ -n "$NO_NETWORK" -o -z "$sched_host$LKP_SERVER$HTTP_PREFIX" ] && {
		echo skip http request: $path "$@"
		return
	}

	([ "${path#http://}" != "$path" ] || [ "${path#https://}" != "$path" ]) && {
		echo \
		$http_client_cmd "$path" "$@"
		$http_client_cmd "$path" "$@"
		return
	}

	# $ busybox wget http://XXX:/
	# wget: bad port spec 'XXX:'
	local http_prefix

	if [ -n "$HTTP_PREFIX" ]; then
		http_prefix="$HTTP_PREFIX"
	elif [ -n "$sched_host" ]; then  # new scheduler
		http_prefix="http://$sched_host:${sched_port:-3000}"
	else
		http_prefix="http://$LKP_SERVER:${LKP_CGI_PORT:-3000}/~$LKP_USER"
	fi

	echo \
	$http_client_cmd "$http_prefix/$path" "$@"
	$http_client_cmd "$http_prefix/$path" "$@"
}

http_setup_client()
{
	[ -n "$http_client_cmd" ] && return

	# use wget of the ppc64le need set secure protocol
	# curl don't need to do that
	[ "$(arch)" = "ppc64le" ] && {
		. $LKP_SRC/lib/curl.sh	&& return
	}
	. $LKP_SRC/lib/curl.sh	&& return
	. $LKP_SRC/lib/wget.sh	&& return

	echo "Cannot find wget/curl." >&2
	return 1
}

check_create_base_dir()
{
	[ -z "$1" ] && return

	local path="$(dirname "$1")"
	[ -d "$path" ] || mkdir -p "$path"
}

http_get_newer_can_skip()
{
	[ -s "$2" ] || return

	# versioned files can be safely cached without checking timestamp
	[ "${1%-????-??-??.cgz}" != "$1" ] && return
	[ "${1%_????-??-??.cgz}" != "$1" ] && return
}

http_get_file()
{
	http_setup_client && http_get_file "$@"
}

http_get_directory()
{
	http_setup_client && http_get_directory "$@"
}

http_get_newer()
{
	http_setup_client && http_get_newer "$@"
}

http_get_cgi()
{
	http_setup_client && http_get_cgi "$@"
}

http_post()
{
	http_setup_client && http_post "$@"
}

# vim:set ts=4 sw=4 et:
